//
//  File.c
//  
//
//  Created by Konstantin Sukharev on 11/17/11.
//  Copyright (c) 2011 __MyCompanyName__. All rights reserved.
//

#define NO (unsigned char) 0
#define YES (unsigned char) 1

typedef enum {
    TypeInt = 0,
    TypeArray
} Type;

typedef enum {
    StmtTypeDeclaration = 0,
    StmtTypeExpr,
    StmtTypeReturn,
    StmtTypeVarDeclaration
} StmtType;

typedef enum {
    ExprTypeId = 0,
    ExprTypeSum,
    ExprTypeMul,
    ExprTypeArrAccess,
    ExprTypeAssign,
    ExprTypeFuncCall,
    ExprTypeConst
} ExprType;

typedef struct {
    StmtType stmtType;
    Expr *expr;
    char *id;
    uint value;
    Stmt *next;
    Type type;
} Stmt;

typedef struct {
    ExprType type;
    char *id;
    uint value;
    Expr *left;
    Expr *right;
    ExprList *list;
    Expr *next;
} Expr;

typedef struct {
    Expr *first;
    Expr *last;
} ExprList;

typedef struct {
    Stmt *first;
    Stmt *last;
} StmtList;

typedef struct {
    QString *name;
    
} Func;

Class Program {
    
    QMap <QString, FuncInfo *> *funcMap;
    QVector <Error *> *errors;
}

Class FuncInfo {
    
    Type retType;
    QVector <Type> *paramTypes;
    QVector <Variable *> *localVars;
    QVector <Error *> *errors;
    
    bool isDeclared(QString *name);
}

Class Variable {
    
    Type type;
    QString *name;
    uint size;
    
    Variable(Type varType, QString *varName, uint varSize);
}

Class Error {
    
    QString *name;
    uint line;
    QString *errDescription;
    
    Error(QString *errName, uint errLine, QString *errDescr);
    
    QString *error();
    uint line();
}

Error (QString *errName, uint errLine, QString *errDescr) {
    
    name = errName->copy();
    line = errLine;
    errDescription = errDescr->copy();
}

void Program::semanticFuncList (FuncList *list) {
    
    Func *current = list->first;
    while (current) {
        this->semanticFunc(current);
        current = current->next;
    }
}

void Program::semanticFunc (Func *func) {
    
    if (funcMap->contains(func->name)) {
        // create and add error;
        errors->append(Error(func->name, /*line*/, QString("func redefinition")));
        return;
    }
    funcMap[func->id] = createFuncInfo(func);
    funcMap[func->id]->semanticStatementList(func->body);
}

FuncInfo *Program::createFuncInfo (Func *func) {
    
    FuncInfo *info = new FuncInfo(/**/);
    
    Stmt *current = func->paramList->first;
    while (current) {
        if (info->isDeclared(current->id)) {
            info->errors->append(Error(current->id, /*line*/, /*descr*/));
        }
        else {
            info->paramTypes->append(Variable(current->id, current->type, current->size));
            current = current->next;
        }
    }
    
    current = func->paramList->first;
    while (current) {
        if (info->isDeclared(current->id)) {
            info->errors->append(Error(current->id, /*line*/, /*descr*/));
        }
        else {
            info->localVars->append(Variable(current->id, current->type, current->size));
            current = current->next;
        }
    }
    
    return 0;
}

void FuncInfo::semanticStatement (Stmt *node) {
    
    switch (node->stmtType) {
        case StmtTypeVarDeclaration:
            if (isDeclared(node->id)) {
                errors->append(Error(node->id, /*line*/, /*descr*/));
                return;
            }
            Variable *var = new Variable(node->type, node->name, node->size);
            lacalVars->append(var);
            break;
        case StmtTypeExpr:
            semanticExpr(node->expr);
            break;
        case StmtTypeReturn:
            if (semanticExpr(node->expr) != TypeInt) {
                // добавление ошибки
                errors->append(Error(QString("incorrect return type"), /*line*/, /*descr*/));
            }
            else {
                retType = TypeInt;
            }
            break;
        default:
            break;
    }
}

Type FuncInfo::semanticExpr(Expr *expr) {
    
    if (expr->type == ExprTypeMul || expr->type == ExprTypeSum || expr->type == ExprTypeAssign) {
        if (semanticExpr(expr->left) == semanticExpr(expr->right) && semanticExpr(expr->left) == TypeInt) {
            return TypeInt;
        }
    }
    if (expr->type == ExprTypeArrAccess) {
        if (semanticExpr(expr->right) == TypeInt && localVars[expr->id]->type == TypeArray) {
            return TypeInt;
        }
    }
    if (expr->type == ExprTypeFuncCall) {
        //проверка, что слева — функция, а справа ЕкспрЛист
    }
    if (expr->type == ExprTypeId) {
        return localVars[expr->id]->type;
    }
    if (expr->type == ExprTypeConst) {
        return TypeInt;
    }
}

void FuncInfo::semanticStatementList(StmtList *list) {
    
    Stmt *stmt = list->first;
    while (stmt) {
        semanticStatement(stmt);
        stmt = stmt->next;
    }
}

bool FuncInfo::isDeclared(QString *name) {
    
    for (uint i = 0; i < localVars->size(); ++i) {
        if (localVars[i]->name->isEqual(name)) {
            return YES;
        }
    }
    return NO;
}


/*
 при ретерне нужно проверить тип экспра и сравнить с возв. знач.
 семЭкспр должно возвр. тип знач. чтобы реализовать контроль типов
 все типы данных должны быть
*/



